package com.member.server.service.impl;

import com.member.server.domain.dto.AccOpDTO;
import com.member.server.domain.dto.AccPayDTO;
import com.member.server.domain.dto.AccRechargeDTO;
import com.member.server.domain.dto.AccRefundDTO;
import com.member.server.domain.param.AccountPayParam;
import com.member.server.domain.param.AccountRechargeParam;
import com.member.server.domain.param.AccountRefundParam;
import com.member.server.entity.*;
import com.member.server.enums.RecordStatus;
import com.member.server.enums.RecordType;
import com.member.server.mapper.*;
import com.member.server.service.IAccountBizService;
import org.springframework.aop.framework.AopContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * @author gaojx1993
 * @version 1.0
 * @description AccountBizServiceImpl
 * @since 2023/7/11 16:09
 */
@Service
public class AccountBizServiceImpl implements IAccountBizService {

    @Resource
    private MemberMapper memberMapper;

    @Resource
    private AccountMapper accountMapper;

    @Resource
    private AccountLogMapper accountLogMapper;

    @Resource
    private RecordMapper recordMapper;

    @Resource
    private RecordAccountPayMapper recordAccountPayMapper;

    @Resource
    private RecordAccountRechargeMapper recordAccountRechargeMapper;

    @Resource
    private RecordAccountRefundMapper recordAccountRefundMapper;

    @Override
    public void accountPay(AccountPayParam accountPayParam) {
        // 校验会员信息
        Member member = getMember(accountPayParam.getMemberId());
        checkMemberValid(member);
        // 获取支付钱包
        List<Account> accounts = getAccounts(member.getId());
        // 是否有可支付钱包
        checkAccounts(accounts);
        // 获取需要保存的支付信息
        AccPayDTO accPayDTO = new AccPayDTO(member, accounts, accountPayParam.getPayAmount());
        // 获取aop代理对象
        AccountBizServiceImpl impl = (AccountBizServiceImpl) AopContext.currentProxy();
        impl.doOperation(accPayDTO);
    }

    @Override
    public void accountRecharge(AccountRechargeParam accountRechargeParam) {
        // 获取充值钱包
        Account account = getAccount(accountRechargeParam.getAccountId());
        // 获取会员信息
        Member member = getMember(account.getMemberId());
        // 检查会员和钱包是否都可用
        checkMemberValid(member);
        checkAccountValid(account);
        // 获取所需保存的充值信息
        AccRechargeDTO accRechargeDTO = new AccRechargeDTO(member, account, accountRechargeParam.getRechargeAmount(), ChannelConfig.mock());
        // 获取aop代理对象
        AccountBizServiceImpl impl = (AccountBizServiceImpl) AopContext.currentProxy();
        impl.doOperation(accRechargeDTO);
    }

    @Override
    public void accountRefund(AccountRefundParam accountRefundParam) {
        // 获取要退款的支付流水
        Record payRecord = getPayRecord(accountRefundParam.getRecordId());
        // 校验支付是否已完成
        checkRecordFinished(payRecord);
        // 获取支付钱包
        List<Account> accounts = getAccounts(payRecord.getMemberId());
        // 获取支付的流水详情
        List<RecordAccountPay> payDetails = recordAccountPayMapper.selectByRecordId(payRecord.getId());
        // 查询该笔支付已经退款的流水详情
        List<RecordAccountRefund> alreadyRefundRecords = recordAccountRefundMapper.selectByPayRecordId(payRecord.getId());
        // 获取所需保存的退款信息
        AccRefundDTO accRefundDTO = new AccRefundDTO(null, accountRefundParam.getRefundAmount(), accounts, payRecord, payDetails, alreadyRefundRecords);
        // 获取aop代理对象
        AccountBizServiceImpl impl = (AccountBizServiceImpl) AopContext.currentProxy();
        impl.doOperation(accRefundDTO);

    }

    @Transactional(rollbackFor = Exception.class)
    public void doOperation(AccOpDTO accOpDTO) {
        // 插入流水
        Record record = accOpDTO.getRecord();
        recordMapper.insert(record);
        if (record.getId() == null) {
            throw new RuntimeException("流水插入失败");
        }

        // 插入账户余额变动记录
        List<AccountLog> accountLogs = accOpDTO.getAccountLogs();
        accountLogs.forEach(al -> al.setRecordId(record.getId()));
        accountLogMapper.insertBatch(accountLogs);

        // 更新账户余额
        for (AccountLog accountLog : accountLogs) {
            accountMapper.updateBalanceById(accountLog.getAfterBalance(), accountLog.getAccountId());
        }

        if (accOpDTO instanceof AccPayDTO) {
            AccPayDTO accPayDTO = (AccPayDTO) accOpDTO;
            // 插入支付流水详情
            List<RecordAccountPay> recordAccountPays = accPayDTO.getRecordAccountPays();
            recordAccountPays.forEach(ap -> ap.setRecordId(record.getId()));
            recordAccountPayMapper.insertBatch(recordAccountPays);
        } else if (accOpDTO instanceof AccRechargeDTO) {
            AccRechargeDTO accRechargeDTO = (AccRechargeDTO) accOpDTO;
            // 插入充值流水详情
            RecordAccountRecharge recordAccountRecharge = accRechargeDTO.getRecordAccountRecharge();
            recordAccountRecharge.setRecordId(record.getId());
            // 调用第三方接口进行支付
            boolean success = doThirdPay(accRechargeDTO);
            if (!success) {
                throw new RuntimeException("充值失败：第三方支付失败！");
            }
            recordAccountRechargeMapper.insert(recordAccountRecharge);
        } else if (accOpDTO instanceof AccRefundDTO) {
            AccRefundDTO accRefundDTO = (AccRefundDTO) accOpDTO;
            // 插入退款流水详情
            List<RecordAccountRefund> recordAccountRefunds = accRefundDTO.getRecordAccountRefunds();
            recordAccountRefunds.forEach(af -> af.setRecordId(record.getId()));
            recordAccountRefundMapper.insertBatch(recordAccountRefunds);
        }
    }


    private Member getMember(Long id) {
        Member member = memberMapper.selectById(id);
        if (member == null) {
            throw new RuntimeException("会员不存在");
        }
        return member;
    }

    private void checkMemberValid(Member member) {
        if (!Boolean.TRUE.equals(member.getValid())) {
            throw new RuntimeException("会员已失效");
        }
    }

    private List<Account> getAccounts(Long memberId) {
        List<Account> accounts = accountMapper.selectByMemberId(memberId);
        if (accounts.isEmpty()) {
            throw new RuntimeException("会员未开通钱包");
        }
        return accounts;
    }

    private void checkAccounts(List<Account> accounts) {
        boolean valid = false;
        for (Account account : accounts) {
            if (Boolean.TRUE.equals(account.getEnabled()) && account.getBalance() > 0) {
                valid = true;
                break;
            }
        }
        if (!valid) {
            throw new RuntimeException("会员无可支付钱包");
        }
    }

    private Account getAccount(Long id) {
        Account account = accountMapper.selectById(id);
        if (account == null) {
            throw new RuntimeException("钱包不存在！");
        }
        return account;
    }

    private void checkAccountValid(Account account) {
        if (!Boolean.TRUE.equals(account.getEnabled())) {
            throw new RuntimeException("钱包已失效");
        }
    }

    private boolean doThirdPay(AccRechargeDTO accRechargeDTO) {

        return true;
    }

    private Record getPayRecord(Long id) {
        Record record = recordMapper.selectByIdAndType(id, RecordType.pay.getCode());
        if (record == null) {
            throw new RuntimeException("支付流水信息不存在！");
        }
        return record;
    }

    private void checkRecordFinished(Record record) {
        if (!Objects.equals(record.getStatus(), RecordStatus.finished.getCode())) {
            throw new RuntimeException("支付未完成，无法退款");
        }
    }

}
